package 网络编程项目.login.utiles;

import 网络编程项目.util.PathUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class ServerToReceiveFile {
  private static ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
  //使用Map保存每个连接，当OP_READ就绪时，根据key找到对应的文件对其进行写入。若将其封装成一个类，作为值保存，可以再上传过程中显示进度等等
  static Map<SelectionKey, FileChannel> fileMap = new HashMap<>();
  public static SelectionKey key = null;

  public void startServer() throws IOException {
    Selector selector = Selector.open();
    ServerSocketChannel serverChannel = ServerSocketChannel.open();
    serverChannel.configureBlocking(false);
    serverChannel.bind(new InetSocketAddress(8888));
    serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    System.out.println("服务器已开启...");
    while (true) {
      int num = selector.select();
      if (num == 0) continue;
      Iterator<SelectionKey> it = selector.selectedKeys().iterator();
      while (it.hasNext()) {
        SelectionKey key = it.next();
        if (key.isAcceptable()) {
          ServerSocketChannel serverChannel1 = (ServerSocketChannel) key.channel();
          SocketChannel socketChannel = serverChannel1.accept();
          if (socketChannel == null) continue;
          socketChannel.configureBlocking(false);
          SelectionKey key1 = socketChannel.register(selector, SelectionKey.OP_READ);
          String ImageName = ImageUtil.getImageName();
          File file = new File(PathUtils.imgDir +"/"+ ImageName + ".jpg");
          System.out.println(file.getPath());
          FileChannel fileChannel = new FileOutputStream(file).getChannel();
          fileMap.put(key1, fileChannel);
          System.out.println(socketChannel.getRemoteAddress() + "连接成功...");
          writeToClient(socketChannel, ImageName);
        } else if (key.isReadable()) {
          readData(key);
        }
        // NIO的特点只会累加，已选择的键的集合不会删除，ready集合会被清空
        // 只是临时删除已选择键集合，当该键代表的通道上再次有感兴趣的集合准备好之后，又会被select函数选中
        it.remove();
      }
    }
  }

  private void writeToClient(SocketChannel socketChannel, String ImageName) throws IOException {
    buffer.clear();
    buffer.put(ImageName.getBytes());
    buffer.flip();
    socketChannel.write(buffer);
    buffer.clear();
  }

  public static void readData(SelectionKey key) throws IOException {
    FileChannel fileChannel = fileMap.get(key);
    buffer.clear();
    SocketChannel socketChannel = (SocketChannel) key.channel();
    int num = 0;
    try {
      while ((num = socketChannel.read(buffer)) > 0) {
        buffer.flip();
        // 写入文件
        fileChannel.write(buffer);
        buffer.clear();
      }
    } catch (IOException e) {
      key.cancel();
      e.printStackTrace();
      return;
    }
    // 调用close为-1 到达末尾
    if (num == -1) {
      fileChannel.close();
      System.out.println("上传完毕");
      key.cancel();
    }
  }
}



